/*
 * Copyright (c) 2018, apexes.net. All rights reserved.
 *
 *         http://www.apexes.net
 *
 */
package net.apexes.commons.ormlite;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.net.Uri;
import android.util.Log;
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.support.ConnectionSource;

import java.io.File;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.List;
import java.util.concurrent.Callable;

/**
 * 
 * @author <a href="mailto:hedyn@foxmail.com">HeDYn</a>
 *
 */
public abstract class SQLiteDatabaseHelper extends OrmLiteSqliteOpenHelper implements DatabaseHelper {
    
    private static final String TAG = SQLiteDatabaseHelper.class.getSimpleName();
    
    private final ChangeSupportable mChangeSupport;

    public SQLiteDatabaseHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion) {
        super(context, databaseName, factory, databaseVersion);
        mChangeSupport = createChangeSupportable(context);
    }

    public SQLiteDatabaseHelper(Context context, String databaseName, CursorFactory factory,
            int databaseVersion, File configFile) {
        super(context, databaseName, factory, databaseVersion, configFile);
        mChangeSupport = createChangeSupportable(context);
    }

    public SQLiteDatabaseHelper(Context context, String databaseName, CursorFactory factory,
            int databaseVersion, InputStream stream) {
        super(context, databaseName, factory, databaseVersion, stream);
        mChangeSupport = createChangeSupportable(context);
    }

    public SQLiteDatabaseHelper(Context context, String databaseName, CursorFactory factory,
            int databaseVersion, int configFileId) {
        super(context, databaseName, factory, databaseVersion, configFileId);
        mChangeSupport = createChangeSupportable(context);
    }
    
    protected ChangeSupportable createChangeSupportable(Context context) {
        return new ContentResolverChangeSupport(context);
    }
    
    @Override
    public <T, ID> Dao<T, ID> dao(Table<T> table) throws SQLException {
        return DatabaseUtil.dao(getConnectionSource(), table);
    }

    @Override
    public <E> E callInTransaction(Callable<E> callable) throws SQLException {
        return DatabaseUtil.callInTransaction(getConnectionSource(), callable);
    }
    
    @Override
    public ChangeSupportable getChangeSupportable() {
        return mChangeSupport;
    }
    
    @Override
    public void onCreate(SQLiteDatabase sqliteDatabase, ConnectionSource connectionSource) {
        try {
            checkSqliteDatabase(sqliteDatabase);
        } catch (Exception ex) {
            Log.e(TAG, "Unable to create database", ex);
        }
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqliteDatabase, ConnectionSource connectionSource, int oldVer, int newVer) {
        try {
            checkSqliteDatabase(sqliteDatabase);
        } catch (Exception ex) {
            Log.e(TAG, "Unable to upgrade database from version " + oldVer + " to new " + newVer, ex);
        }
    }

    protected void checkSqliteDatabase(SQLiteDatabase db) throws Exception {
        SqliteUpgrader upgrader = new SqliteUpgrader(db, getTables());
        upgrader.upgrade(getConnectionSource());
    }
    
    /**
     * 返回包含所有数据表的列表
     * @return
     */
    protected abstract List<Table<?>> getTables();

    /**
     * 返回指定数据表的uri
     * @param table
     * @return
     */
    protected abstract Uri getUri(Table<?> table);
    
    /**
     * 
     * @author <a href="mailto:hedyn@foxmail.com">HeDYn</a>
     *
     */
    protected class ContentResolverChangeSupport extends AbstractChangeSupport {
        
        private final Context mContext;
        
        protected ContentResolverChangeSupport(Context context) {
            mContext = context;
        }
        
        protected void notifyChange(Uri uri) {
            mContext.getContentResolver().notifyChange(uri, null);
        }
        
        @Override
        protected void notifyChange(Table<?>... tables) {
            for (Table<?> table : tables) {
                notifyChange(getUri(table));
            }
        }
    }
}
